
function createSphereVertices(//画球
	radius,//半径
	subdivisionsAxis,//细分
	subdivisionsHeight,//细分
	opt_startLatitudeInRadians=0,//纬度开始角度
	opt_endLatitudeInRadians=Math.PI,//纬度结束角度
	opt_startLongitudeInRadians=0,//经度开始角度
	opt_endLongitudeInRadians=Math.PI * 2//经度结束角度
	) {
  if (subdivisionsAxis <= 0 || subdivisionsHeight <= 0) {//细分不能小于1
	throw Error('细分需要大于0');
  }
  const latRange = opt_endLatitudeInRadians - opt_startLatitudeInRadians;//纬度画的范围
  const longRange = opt_endLongitudeInRadians - opt_startLongitudeInRadians;//经度画的范围
  // 1 1
  // (1+1) * (1+1)
  // 2*2=4
  //细分一次 变成两块 细分两次 变成三块
  const numVertices = (subdivisionsAxis + 1) * (subdivisionsHeight + 1);
  const positions = createAugmentedTypedArray(3, numVertices);//用来存3个顶点numVertices组
  const normals   = createAugmentedTypedArray(3, numVertices);
  const texCoords = createAugmentedTypedArray(2 , numVertices);

  // Generate the individual vertices in our vertex buffer.
  for (let y = 0; y <= subdivisionsHeight; y++) {//循环高细分
	for (let x = 0; x <= subdivisionsAxis; x++) {//循环环细分
		const u = x / subdivisionsAxis;//x分割比例
		const v = y / subdivisionsHeight;//y分割比例
		const theta = longRange * u + opt_startLongitudeInRadians;//longRange总细分，u百分百，opt_startLongitudeInRadians开始度数
		//计算出来的是原点到顶点的度数，分成环
		// 总细分3 当前1 = 0.33
		// 设结束度数 Math.PI*2 开始度数 0  longRange = Math.PI*2 * 0.3 + 经度开始角度0
		//  Math.PI*2 * 0.66 + 经度开始角度0//第二个
		//  Math.PI*2 * 1 + 经度开始角度0//第三个
		// [ Math.PI*2 * 0.3 , Math.PI*2 * 0.66 ,  Math.PI*2 * 1 ]
		const phi = latRange * v + opt_startLatitudeInRadians;
		//一个经度的角度一个纬度的角度 theta phi

		const sinTheta = Math.sin(theta);//x
		const cosTheta = Math.cos(theta);//x
		const sinPhi = Math.sin(phi);//y
		const cosPhi = Math.cos(phi);//y
		const ux = cosTheta * sinPhi;
		const uy = cosPhi;//cos(y)
		const uz = sinTheta * sinPhi;//对边*对边
		/*
		[
			cos,sin,0,
			sin,-cos,0,
			0,0,0,
		]
			|
		   ||
		  | |
		  x
		  y

		*/
		positions.push(radius * ux, radius * uy, radius * uz);//对边就是x，斜边就是radius，sin*半径=对边=x，cos*半径=邻边=y
		normals.push(ux, uy, uz);
		texCoords.push(1 - u, v);
	}
  }

  const numVertsAround = subdivisionsAxis + 1;
  const indices = createAugmentedTypedArray(3, subdivisionsAxis * subdivisionsHeight * 2, Uint16Array);//Uint16Array(3*subdivisionsAxis * subdivisionsHeight * 2)
  for (let x = 0; x < subdivisionsAxis; x++) {
	for (let y = 0; y < subdivisionsHeight; y++) {
	  indices.push(
		  (y + 0) * numVertsAround + x,//分段数设为3，则numVertsAround为4，(y+0)*4+x
		  (y + 0) * numVertsAround + x + 1,//(y+0)*4+x+1
		  (y + 1) * numVertsAround + x);//(y+1)*4+x
		
	  indices.push(
		  (y + 1) * numVertsAround + x,
		  (y + 0) * numVertsAround + x + 1,
		  (y + 1) * numVertsAround + x + 1);
	}
  }

  return {
	position: positions,
	normal: normals,
	texcoord: texCoords,
	indices: indices,
  };
}
/**
 * 
 * @param {*} numComponents 一个数据多少长
 * @param {*} numElements 有几个数据
 * @param {*} opt_type [可选]数据类型，默认Float32Array
 */
function createAugmentedTypedArray(numComponents, numElements, opt_type) {
    const Type = opt_type || Float32Array;
    return augmentTypedArray(new Type(numComponents * numElements), numComponents);
}
function augmentTypedArray(typedArray, numComponents) {
    let cursor = 0;
    typedArray.push = function() {//添加值的方法可以添加数组，类型数组，值
      for (let ii = 0; ii < arguments.length; ++ii) {
        const value = arguments[ii];
        if (value instanceof Array || (value.buffer && value.buffer instanceof ArrayBuffer)) {//buffer数据类型
          for (let jj = 0; jj < value.length; ++jj) {
            typedArray[cursor++] = value[jj];
          }
        } else {//增加一个值
          typedArray[cursor++] = value;
        }
      }
    };
    typedArray.reset = function(opt_index) {//重置值偏移位置
      cursor = opt_index || 0;
    };
    typedArray.numComponents = numComponents;//数据长
    Object.defineProperty(typedArray, 'numElements', {//总数据有多少个
      get: function() {
        return this.length / this.numComponents | 0;
      },
    });
    return typedArray;//返回一个有 push reset numComponents numElements属性方法的数组或类数组
  }
function createBufferInfoFromArrays(gl, arrays, opt_mapping) {
    const bufferInfo = {
      attribs: createAttribsFromArrays(gl, arrays, opt_mapping),
    };
    let indices = arrays.indices;
    if (indices) {
      indices = makeTypedArray(indices, 'indices');
      bufferInfo.indices = createBufferFromTypedArray(gl, indices, gl.ELEMENT_ARRAY_BUFFER);
      bufferInfo.numElements = indices.length;
    } else {
      bufferInfo.numElements = getNumElementsFromNonIndexedArrays(arrays);
    }

    return bufferInfo;
}
var arrays = {
	position: { numComponents: 3, data: [0, -10, 0, 10, 10, 0, -10, 10, 0], },
	texcoord: { numComponents: 2, data: [0.5, 0, 1, 1, 0, 1],               },
	normal:   { numComponents: 3, data: [0, 0, 1, 0, 0, 1, 0, 0, 1],        },
};
function getNumElementsFromNonIndexedArrays(arrays) {//[]
	let key;
	for (const k of positionKeys) {
		if (k in arrays) {
		key = k;
		break;
		}
	}
	key = key || Object.keys(arrays)[0];
	const array = arrays[key];
	const length = getArray(array).length;
	const numComponents = getNumComponents(array, key);
	const numElements = length / numComponents;
	if (length % numComponents > 0) {
		throw new Error(`numComponents ${numComponents} not correct for length ${length}`);
	}
	return numElements;
}
function getArray(array) {
    return array.length ? array : array.data;
  }
